package com.uuah.server.transport;

import com.uuah.api.work.IWorkManager;
import com.uuah.exception.lifecycle.CreateException;
import com.uuah.exception.lifecycle.InitialisationException;
import com.uuah.server.UuahEvent;
import com.uuah.server.api.IUuahEvent;
import com.uuah.server.api.IUuahMessage;
import com.uuah.server.api.component.service.IService;
import com.uuah.server.api.endpoint.IEndpointURI;
import com.uuah.server.api.endpoint.IUuahEndpoint;
import com.uuah.server.api.session.IUuahSession;
import com.uuah.server.api.transport.IConnector;
import com.uuah.server.api.transport.IMessageReceiver;
import com.uuah.server.api.transport.InternalMessageListener;
import com.uuah.server.exception.AbstractUuahServerException;
import com.uuah.server.session.UuahSession;
import com.uuah.utils.ClassUtils;
import com.uuah.utils.StringUtils;

/**
 * <code>AbstractMessageReceiver</code> provides common methods for all Message
 * Receivers provided with Uuah App Server. A message receiver enables an endpoint to
 * receive a message from an external system.
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午03:12:52
 * @version 1.0.0
 */
public abstract class AbstractMessageReceiver extends AbstractConnectable
		implements IMessageReceiver {
	protected IService service = null;

	private InternalMessageListener listener;

	protected String receiverKey = null;

	private IEndpointURI endpointUri;

	public AbstractMessageReceiver(IConnector connector, IService service,
			IUuahEndpoint endpoint) throws CreateException {
		super(endpoint);

		setService(service);
	}

	public final void initialise() throws InitialisationException {
		super.initialise();

		listener = new DefaultInternalMessageListener();
		endpointUri = endpoint.getEndpointURI();

		doInitialise();
	}

	public final synchronized void dispose() {
		super.dispose();
		try {
			disposing.set(true);
			doDispose();
		} finally {
			disposed.set(true);
		}
	}

	public IService getService() {
		return service;
	}

	public final IUuahMessage routeMessage(IUuahMessage message)
			throws AbstractUuahServerException {
		return routeMessage(message, endpoint.isSynchronous());
	}

	public final IUuahMessage routeMessage(IUuahMessage message,
			boolean synchronous) throws AbstractUuahServerException {

		if (logger.isDebugEnabled()) {
			logger.debug("Message Received from: " + endpoint.getEndpointURI());
		}
		if (logger.isTraceEnabled()) {
			try {
				logger.trace("Message Payload: \n"
						+ StringUtils.truncate(StringUtils.toString(message
								.getPayload()), 200, false));
			} catch (Exception e) {
				// ignore
			}
		}

		return listener.onMessage(message, synchronous);
	}

	protected IUuahMessage handleUnacceptedFilter(IUuahMessage message) {
		String messageId;
		messageId = message.getUniqueId();

		if (logger.isDebugEnabled()) {
			logger.debug("Message " + messageId
					+ " failed to pass filter on endpoint: " + endpoint
					+ ". Message is being ignored");
		}

		return message;
	}

	public void setService(IService service) {
		if (service == null) {
			throw new IllegalArgumentException("Service cannot be null");
		}
		this.service = service;
	}

	public IEndpointURI getEndpointURI() {
		return endpointUri;
	}

	public String getConnectionDescription() {
		return endpoint.getEndpointURI().toString();
	}

	public InternalMessageListener getListener() {
		return listener;
	}

	public void setListener(InternalMessageListener listener) {
		this.listener = listener;
	}

	private class DefaultInternalMessageListener implements
			InternalMessageListener {

		public IUuahMessage onMessage(IUuahMessage message, boolean synchronous)
				throws AbstractUuahServerException {
			IUuahMessage resultMessage = null;
			IUuahSession session = new UuahSession(message, connector
					.getSessionHandler(), service, connector.getUuahContext());
			IUuahEvent uuahEvent = new UuahEvent(message, endpoint, session,
					synchronous);
			uuahEvent = RequestContextHelper.unsafeSetEvent(uuahEvent);

			resultMessage = service.getRequestChannel().route(uuahEvent);

			if (resultMessage != null) {
				if (resultMessage.getExceptionPayload() != null) {
					// TODO
				}
				resultMessage.applyTransformer(endpoint
						.getResponseTransformer());
			}
			return resultMessage;
		}
	}

	protected String getConnectEventId() {
		return connector.getName() + ".receiver (" + endpoint.getEndpointURI()
				+ ")";
	}

	public void setReceiverKey(String receiverKey) {
		this.receiverKey = receiverKey;
	}

	public String getReceiverKey() {
		return receiverKey;
	}

	public IUuahEndpoint getEndpoint() {
		return (IUuahEndpoint) super.getEndpoint();
	}

	public void setEndpoint(IUuahEndpoint endpoint) {
		super.setEndpoint(endpoint);
	}

	protected IWorkManager getWorkManager() {
		try {
			return connector.getReceiverWorkManager("receiver");
		} catch (AbstractUuahServerException e) {
			logger.error(e.getMessage());
			return null;
		}
	}

	public String toString() {
		final StringBuffer sb = new StringBuffer(80);
		sb.append(ClassUtils.getSimpleName(this.getClass()));
		sb.append("{this=").append(
				Integer.toHexString(System.identityHashCode(this)));
		sb.append(", receiverKey=").append(receiverKey);
		sb.append(", endpoint=").append(endpoint.getEndpointURI());
		sb.append('}');
		return sb.toString();
	}
}
